package com.aijk.commons.utils;

import com.aijk.commons.exception.ErrorCodeConst;
import com.aijk.commons.exception.ErrorCodeException;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 基于 httpclient 4.3.1版本的 http工具类
 *
 * @author chendw
 */
public class HttpUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpUtils.class);

    private static final CloseableHttpClient httpClient;
    public static final String CHARSET = "UTF-8";

    static {
        RequestConfig config = RequestConfig.custom().setConnectTimeout(60000).setSocketTimeout(15000).build();
        httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
    }

    private HttpUtils() {

    }

    /**
     * GET请求
     *
     * @param url    请求地址
     * @param params 请求参数
     * @return
     */
    public static String doGet(String url, Map<String, String> params) {
        return doGet(url, params, CHARSET);
    }

    /**
     * GET请求
     *
     * @param url 请求地址
     * @return
     */
    public static String doGet(String url) {
        return doGet(url, null, CHARSET);
    }

    /**
     * HTTP Get 获取内容
     *
     * @param url     请求的url地址 ?之前的地址
     * @param params  请求的参数
     * @param charset 编码格式
     * @return 页面内容
     */
    public static String doGet(String url, Map<String, String> params, String charset) {
        if (StringUtils.isBlank(url)) {
            return null;
        }

        HttpGet httpGet = new HttpGet(url);
        CloseableHttpResponse response = null;
        try {
            if (params != null && !params.isEmpty()) {
                List<NameValuePair> pairs = parsePairs(params);
                url += "?" + EntityUtils.toString(new UrlEncodedFormEntity(pairs, charset));
            }

            response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            String result = null;
            if (entity != null) {
                result = EntityUtils.toString(entity, charset);
            }
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                throw new ErrorCodeException(ErrorCodeConst.GLOBAL_RESPONSE_ERROR, "HttpClient,error status code :" + statusCode + ", body :" + result);
            }

            return result;
        } catch (Exception e) {
            LOGGER.error("get请求异常", e);
        } finally {
            httpGet.abort();
            if (response != null) {
                EntityUtils.consumeQuietly(response.getEntity());
                try {
                    response.close();
                } catch (IOException e) {
                    LOGGER.error(e.getMessage(), e);
                }
            }
        }
        return null;
    }

    /**
     * POST请求
     *
     * @param url    请求地址
     * @param params 请求参数
     * @return
     */
    public static String doPost(String url, Map<String, String> params) {
        return doPost(url, params, CHARSET);
    }

    /**
     * POST请求
     *
     * @param url 请求地址
     * @return
     */
    public static String doPost(String url) {
        return doPost(url, null, CHARSET);
    }

    /**
     * HTTP Post 获取内容
     *
     * @param url     请求的url地址 ?之前的地址
     * @param headers 请求的header
     * @param params  请求的参数
     * @return 页面内容
     */
    public static String doPost(String url, Map<String, String> headers, Map<String, String> params) {
        return doPost(url, headers, params, CHARSET);
    }

    /**
     * HTTP Post 获取内容
     *
     * @param url     请求的url地址 ?之前的地址
     * @param params  请求的参数
     * @param charset 编码格式
     * @return 页面内容
     */
    public static String doPost(String url, Map<String, String> params, String charset) {
        return doPost(url, null, params, charset);
    }

    /**
     * HTTP Post 获取内容
     *
     * @param url     请求的url地址 ?之前的地址
     * @param params  请求的参数
     * @param charset 编码格式
     * @return 页面内容
     */
    public static String doPost(String url, Map<String, String> header, Map<String, String> params, String charset) {
        return doPost(url, header, params, null, null, charset);
    }

    /**
     * Http Post Body
     *
     * @param url    请求的url地址 ?之前的地址
     * @param header 请求的header
     * @param body   请求内容
     * @return
     */
    public static String doPostBody(String url, Map<String, String> header, String body) {
        return doPost(url, header, null, null, body, CHARSET);
    }

    /**
     * Http Post Body
     *
     * @param url      请求的url地址 ?之前的地址
     * @param header   请求的header
     * @param mimeType 请求类型  ContentType
     * @param body     请求内容
     * @return
     */
    public static String doPostBody(String url, Map<String, String> header, String mimeType, String body) {
        return doPost(url, header, null, mimeType, body, CHARSET);
    }

    /**
     * <per> HTTP Post 获取内容 </per>
     *
     * @param url      请求的url地址 ?之前的地址
     * @param params   请求的参数，当body不为空时，该参数会被忽略
     * @param charset  编码格式
     * @param mimeType 请求类型  ContentType
     * @param body     正文
     * @return 页面内容
     */
    public static String doPost(String url, Map<String, String> header, Map<String, String> params, String mimeType, String body, String charset) {
        if (StringUtils.isBlank(url)) {
            return null;
        }

        HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse response = null;
        try {


            List<NameValuePair> pairs = parsePairs(params);
            if (CollectionUtils.isNotEmpty(pairs)) {
                httpPost.setEntity(new UrlEncodedFormEntity(pairs, charset));
            }

            if (body != null) {
                httpPost.setEntity(new StringEntity(body, mimeType, charset));
            }

            // Add Header
            if (MapUtils.isNotEmpty(header)) {
                for (Map.Entry<String, String> entry : header.entrySet()) {
                    String value = entry.getValue();
                    if (value != null) {
                        httpPost.addHeader(entry.getKey(), value);
                    }
                }
            }

            response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            String result = null;
            if (entity != null) {
                result = EntityUtils.toString(entity, charset);
            }
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                throw new ErrorCodeException(ErrorCodeConst.GLOBAL_RESPONSE_ERROR, "HttpClient,error status code :" + statusCode + ", body :" + result);
            }
            return result;
        } catch (Exception e) {
            LOGGER.error("post请求异常", e);
        } finally {
            httpPost.abort();
            if (response != null) {
                EntityUtils.consumeQuietly(response.getEntity());
                try {
                    response.close();
                } catch (IOException e) {
                    LOGGER.error(e.getMessage(), e);
                }
            }
        }
        return null;
    }

    public static List<NameValuePair> parsePairs(Map<String, String> params) {
        List<NameValuePair> pairs = new ArrayList<>();
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                String value = entry.getValue();
                if (value != null) {
                    pairs.add(new BasicNameValuePair(entry.getKey(), value));
                }
            }
        }
        return pairs;
    }
}